// Copyright (c) 2009 Mike Haight, Andy Kipp
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include "stdafx.h"

generic<typename T>ParticleSystem<T>::ParticleSystem(ParticleSettings^ argParticleSettings) : mParticleSettings(argParticleSettings)
{
}


generic<typename T> Coordinates::Location ParticleSystem<T>::Origin::get(void)
{
    return mOrigin;
}


generic<typename T> void ParticleSystem<T>::Origin::set(Coordinates::Location value)
{
    mOrigin = value;
}


generic<typename T> bool ParticleSystem<T>::Regenerate::get(void)
{
    return mRegenerate;
}


generic<typename T> void ParticleSystem<T>::Regenerate::set(bool value)
{
    mRegenerate = value;
}


generic<typename T> T ParticleSystem<T>::CreateParticle(void)
{
    T particle = (T)Activator::CreateInstance(T::typeid, gcnew array<Object^> { mParticleSettings });
    particle->Origin = mOrigin;
    particle->Location = mOrigin;

    // Bring Particle to Life
    particle->Begin();
    return particle;
}


generic<typename T> void ParticleSystem<T>::RegenerateParticle(T argParticle)
{
    argParticle->Origin = mOrigin;
    argParticle->Location = mOrigin;

    // Bring Particle to Life
    argParticle->Begin();
}


generic<typename T> void ParticleSystem<T>::Begin(void)
{
    // Get a random number of Particles to create
    int createCount = smRandom->Next(mParticleSettings->MinParticles, mParticleSettings->MaxParticles + 1);

    smLogger->Info("Begin Particle System with {0} particles.", createCount);

    // Create Particles
    for (int p = 0; p < createCount; p++)
    {
        // Create Particle
        T particle = CreateParticle();

        // Add Particle to Particle List
        mParticles.Add(particle);
    }
}


generic<typename T> void ParticleSystem<T>::End(void)
{
    smLogger->Info("End Particle System.");

    // End Particle's Life
    for each (T particle in mParticles)
    {
        particle->End();
    }

    // Clear Particle List
    mParticles.Clear();
}


generic<typename T> void ParticleSystem<T>::Update(void)
{
    int particleCount = mParticles.Count;

    // Update Particles
    {
        for (int p = 0; p < mParticles.Count; p++)
        {
            // Get Particle
            T particle = mParticles[p];

            // Check if Particle is Alive
            if (particle->Life > 0)
            {

                // Update Particle
                particle->Update();

            } else {

                // End Particle's Life
                particle->End();

                // Regenerate Dead Particles
                if (mRegenerate)
                {
                    RegenerateParticle(particle);

                    // Update Particle
                    particle->Update();

                }

            }
        }
    }
}


generic<typename T> void ParticleSystem<T>::GetSprites(List<Sprite^>^ argSpriteList)
{
    for each (Particle^ particle in mParticles)
    {
        particle->GetSprites(argSpriteList);
    }
}